/**
 **oj/math - Math functions
 *
 * The math module provides a number of mathematical functions.
 *
 */

define([], function() {
    'use strict';
    
    window['math'] = {};
    
    
    var ONETHIRD = 1/3,
        ONESIXTH = 1/6,
        T = [0x15, 0x38, 0x32, 0x2c, 0x0d, 0x13, 0x07, 0x2a],
        A = [0, 0, 0], s, X, Y, Z, u, v, w, i, j, k, hi, lo, t, p, q, r, h,
        b1, b2, b3, b4, b5;
    
   
    function G (a) {
        /* Returns the hashed gradient indices of a specified corner. */
        
        s = (A[0] + A[1] + A[2]) * ONESIXTH;
        X = u - A[0] + s;
        Y = v - A[1] + s;
        Z = w - A[2] + s;
        t = 0.6 - X * X - Y * Y - Z * Z;
        p = i + A[0];
        q = j + A[1];
        r = k + A[2];
        h = T[(p & 1) << 2 | (q & 1) << 1 | (r & 1)] +
            T[(q >> 1 & 1) << 2 | (r >> 1 & 1) << 1 | (p >> 1 & 1)] +
            T[(r >> 2 & 1) << 2 | (p >> 2 & 1) << 1 | (q >> 2 & 1)] +
            T[(p >> 3 & 1) << 2 | (q >> 3 & 1) << 1 | (r >> 3 & 1)] +
            T[(q >> 4 & 1) << 2 | (r >> 4 & 1) << 1 | (p >> 4 & 1)] +
            T[(r >> 5 & 1) << 2 | (p >> 5 & 1) << 1 | (q >> 5 & 1)] +
            T[(p >> 6 & 1) << 2 | (q >> 6 & 1) << 1 | (r >> 6 & 1)] +
            T[(q >> 7 & 1) << 2 | (r >> 7 & 1) << 1 | (p >> 7 & 1)];
        A[a]++;
        if (t < 0) {
            return 0;
        }
        b5 = h >> 5 & 1;
        b4 = h >> 4 & 1;
        b3 = h >> 3 & 1;
        b2 = h >> 2 & 1;
        b1 = h & 3;
    
        if (b1 === 1) {
            p = X;
            q = Y;
            r = Z;
        } else if (b1 === 2) {
            p = Y;
            q = Z;
            r = X;
        } else {
            p = Z;
            q = X;
            r = Y;
        }
        if (b5 === b3) {
            p = -p;
        }
        if (b5 === b4) {
            q = -q;
        }
        if (b5 !== (b4^b3)) {
            r = -r;
        }
        t *= t;
        
        return (t * t * (p + ((b1 === 0) ? q + r : (b2 === 0) ? q : r)));
    }
    
    
    math['noise'] = function(x, y, z) {
        /**
         *> math.noise(x, y, z)
         *
         * Returns the simplex noise function value between -1.0 and 1.0.
         */
        
        // skew input space to relative coordinate in simplex cell
        s = (x + y + z) * ONETHIRD; // nice skew factor for 3d
        i = (x + s) | 0;
        j = (y + s) | 0;
        k = (z + s) | 0;
        
        // unskew cell origin back to (x, y, z) space
        s = (i + j + k) * ONESIXTH; // nice unskew factor for 3d
        u = x - i + s;
        v = y - j + s;
        w = z - k + s;
        
        // for 3d the simplex shape is a slightly irregular tetrahedron
        // determine which simplex we are in
        if (u < w) {
            lo = (u < v) ? 0 : 1;
            hi = (v >= w) ? 1 : 2;
        } else {
            lo = (v < w) ? 1 : 2;
            hi = (u >= v) ? 0 : 1;
        }
        
        A[0] = A[1] = A[2] = 0;
        
        // calculate the contribution from the four corners
        return 8 * (G(hi) + G(3 - hi - lo) + G(lo) + G(0));
    };
    
    return math;
    
});